#include "ahudata.h"

extern ahu_dev_t *ahu_dev_hd;
extern struct mosquitto *mqtt_ahu;

/* 设置设备描述符中的点位的value
 * @pp: 设备描述符中点位
 * @val: 要设置的值
 * @tp: 值的类型
 */
void setval_2dev(point_prop_t *pp, data_type_u val, enum type_of_val tp)
{
    switch(tp){
    case TypeOfVal_BOOL:
        pp->val.b = val.b;
        break;

    case TypeOfVal_INT:
        pp->val.i = val.i;
        break;

    case TypeOfVal_DOUBLE:
        pp->val.d = val.d;
        break;
    case TypeOfVal_STRING:
        strcpy(pp->val.s, val.s);
        break;

    default:
        break;
    }

    pp->tag = tp;
}

/* 组装write命令：
{
    "deviceKey" : "@dk",
    "cmd":"write",
    "function" :
    {
        "@chan": @val,
    }
}
 */
void combine_wr_cmd_bypp(struct json_object *jroot, point_prop_t *pp)
{
    /* 创建json deviceKey 字段 */
    struct json_object *jdk = json_object_new_string(pp->dev_key);
    json_object_object_add(jroot, "deviceKey", jdk);
    /* 创建json write 字段 */
    struct json_object *jcmd = json_object_new_string("write");
    json_object_object_add(jroot, "cmd", jcmd);
    
    /* 创建json function 字段 */
    struct json_object *jfunc = json_object_new_object();
    struct json_object *jval;

    /* 创建value */
    if(pp->tag == TypeOfVal_BOOL){
        jval = json_object_new_boolean(pp->val.b);
    }else if(pp->tag == TypeOfVal_DOUBLE){
        jval = json_object_new_double(pp->val.d);
    }else if(pp->tag == TypeOfVal_INT){
        jval = json_object_new_int(pp->val.i);
    }else if(pp->tag == TypeOfVal_STRING){
        jval = json_object_new_string(pp->val.s);
    }

    json_object_object_add(jfunc, pp->func, jval);

    json_object_object_add(jroot, "function", jfunc);
}

/* 将点位的deviceKey、function、value组装成json报文通过mqtt发送出去
 * @name: 点位name
 * @dev_prop: 点位指针
 */
void sendpoint_2otherapp(point_prop_t *pp)
{
    /* 组装json报文 */
    struct json_object *jroot = json_object_new_object();
    combine_wr_cmd_bypp(jroot, pp);
    const char *tx_buf = json_object_to_json_string_ext(jroot, JSON_C_TO_STRING_PRETTY);

    /* mqtt send */
    char topic[120];
    sprintf(topic, "%s/%s/command", MQTT_LOCAL_PREFIX, pp->dev_key);
    mosquitto_publish(mqtt_ahu, NULL, topic, strlen(tx_buf), tx_buf, 0, 0);

    printf("AHU: send json to %s:\n %s \n", topic, tx_buf);

    json_object_put(jroot);
}

/* 如果@name表示的点位存在，就将@val的值配置到@ahu_dev表示的设备中， 并且将这个name点位组装成json报文发送出去
 * @name: 要设置并发送的点位
 * @ahu_dev：设备
 * @val：value
 * @tp：value的类型
 */
enum error_code set_cmdpoint_ifexist(char *name, ahu_dev_t *ahu_dev, data_type_u val, enum type_of_val tp)
{
    int i;
    /* 遍历虚点 */
    for(i=0; i<ahu_dev->vir_num; i++){
        if(strcmp((ahu_dev->vp+i)->name, name) == 0){
            /* 设置value到设备描述符中 */
            setval_2dev(ahu_dev->vp+i, val, tp);
            /* 将点位发送出去 */
            sendpoint_2otherapp(ahu_dev->vp+i);
            return Success;
        }
    }

    for(i=0; i<ahu_dev->real_num; i++){
        if(strcmp((ahu_dev->rp+i)->name, name) == 0){
            setval_2dev(ahu_dev->rp+i, val, tp);
            sendpoint_2otherapp(ahu_dev->rp+i);
            return Success;
        }
    }

    return ErrNoExist;
}

/* 根据虚点位@name，从@ahu_dev设备中读这个点位的值，保存到@val中 */
enum error_code read_vp_byname(ahu_dev_t *ahu_dev, char *name, data_type_u *val)
{
    int i;
    /* 遍历虚点 */
    for(i=0; i<ahu_dev->vir_num; i++){
        if(strcmp((ahu_dev->vp+i)->name, name) == 0){
            memcpy(val, &((ahu_dev->vp+i)->val), sizeof(data_type_u));
            return Success;
        }
    }
    return ErrExist;
}

/* 根据实点位@name，从@ahu_dev设备中读这个点位的值，保存到@val中 */
enum error_code read_rp_byname(ahu_dev_t *ahu_dev, char *name, data_type_u *val)
{
    int i;
    /* 遍历实点 */
    for(i=0; i<ahu_dev->real_num; i++){
        if(strcmp((ahu_dev->rp+i)->name, name) == 0){
            memcpy(val, &((ahu_dev->rp+i)->val), sizeof(data_type_u));
            return Success;
        }
    }

    return ErrNoExist;
}

/* 将两个字符串组合成一个 */
void combine_string(char *dest, char *src1, char *src2)
{
    strcat(dest, src1);
    strcat(dest, src2);
}

/* 根据点位name找到double类型的点位，返回其value的地址
 * note: 调用者要知道自己要找到的点位的value是double型
 */
double *get_double_ptr_by_name(char *name, ahu_dev_t *ahu_dev)
{
    int i;
    double *ret = NULL;
    /* 遍历虚点 */
    for(i=0; i<ahu_dev->vir_num; i++){
        if(strcmp((ahu_dev->vp+i)->name, name) == 0){
            ret = &(ahu_dev->vp+i)->val.d;
            return ret;
        }
    }
    /* 遍历实点 */
    for(i=0; i<ahu_dev->real_num; i++){
        if(strcmp((ahu_dev->rp+i)->name, name) == 0){
            ret = &(ahu_dev->rp+i)->val.d;
            return ret;
        }
    }

    return ret;
}

/* 判断设备@ahu_dev中是否存在点位@name，存在就返回true */
bool is_point_exist(ahu_dev_t *ahu_dev, char *name)
{
    int i;

    for(i=0; i<ahu_dev->vir_num; i++){
        if(strcmp((ahu_dev->vp+i)->name, name) == 0){
            return true;
        }
    }

    for(i=0; i<ahu_dev->real_num; i++){
        if(strcmp((ahu_dev->rp+i)->name, name) == 0){
            return true;
        }
    }

    return false;
}

/* 当设备运行后，会更新一些点位的属性，比如运行时间，冬夏季转换标志位等 */
void *ahu_rt_update_thread(void *arg)
{
    pthread_detach(pthread_self());

    /* WS_EX: 冬夏季节转换val */
    data_type_u val_ws_ex;

    ahu_dev_t *pos;
    
    while(1){
        sleep(2);
        /* 遍历所有的设备 */
        list_for_each_entry(pos, &ahu_dev_hd->list, list){
            /* 从设备中读取WS-EX的value */
            read_vp_byname(pos, "WS-EX", &val_ws_ex);
            /* 比较新value和老value，如果不一致，就设置标志为CHANGED */
            if(pos->pidset.season == val_ws_ex.i){
                pos->pidset.changed = !CHANGED;

            }else{
                ES_PRT_INFO("AHU: dev_id[%s], Season is changed from %d to %d, (1:winter, 2:summer, 3:transition) \n", pos->device_id, pos->pidset.season, val_ws_ex.i);
                pos->pidset.changed = CHANGED;
            }

            pos->pidset.season = val_ws_ex.i;
        }
        
    }

    return NULL;
}